package tencent_game_server;

import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import util.JsonUtil;



public class Server implements IServer,Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = -3927296302878169916L;
	public static final int PORT = 12345;//监听的端口号   
	public static IGameServer gServer;
    public static void main(String[] args) {  
        System.out.println("服务器启动...\n");  
        Server server = new Server();  
        Registry reg=null;
        Remote remote=null;
        	
//        	try {
//				reg=LocateRegistry.getRegistry(8888);
//			} catch (RemoteException e) {
//				// TODO Auto-generated catch block
//				//e.printStackTrace();
//			}

        
			try {
//				if(reg==null)
					LocateRegistry.createRegistry(8888);
//				if(Naming.lookup("rmi://localhost:8888/server")!=null)
//					Naming.unbind("rmi://localhost:8888/server");
				Naming.bind("rmi://localhost:8888/server",server); 
				server.startGameServer();
				server.init(); 
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (AlreadyBoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
			
		try {
			Naming.unbind("rmi://localhost:8888/server");
		} catch (RemoteException | MalformedURLException | NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        System.out.println("服务器关闭\n");  
		
    }  
    private void startGameServer(){
    	Thread thread=new Thread(new  Runnable() {
			public void run() {
		        ArrayList<String> list = new ArrayList<String>();  
		        ProcessBuilder pb = null;  
		        Process p = null;      
		        String java = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";  
		        String classpath = System.getProperty("java.class.path");  
		        list.add(java);  
		        list.add("-classpath");  
		        list.add(classpath);  
		        list.add(GameServer.class.getName());  
		        pb = new ProcessBuilder(list);  
		        
		        try {
					p = pb.start();
					InputStream   in=p.getInputStream();
					Scanner sc=new Scanner(in);
					while(sc.hasNext()){
						System.out.println("Gameser : "+sc.nextLine());
					}
					sc.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
    	thread.start();
        
    }
    private static HashMap<String,HandlerThread> handlerThreads=new HashMap<>();
    public static void  add(String s,HandlerThread ht) {
		synchronized (handlerThreads) {
			handlerThreads.put(s, ht);
		}
	}
    public static void  remove(String s) {
  		synchronized (handlerThreads) {
  			handlerThreads.remove(s);
  		}
  	}
    public void init() {  
    	ServerSocket serverSocket=null;
        try {  
        	serverSocket = new ServerSocket(PORT);  
            while (true) {   
                Socket client = serverSocket.accept();   
                new HandlerThread(client);  
            }  
            
        } catch (Exception e) {  
        	
            System.out.println("服务器异常: " + e.getMessage());  
        }  
        
    }


    private class HandlerThread implements Runnable {  
        private Socket socket;
        private IGameServer gameServer;
        private String userName="";
        private DataInputStream inputStream = null;
        private DataOutputStream outputStream = null;
        public HandlerThread(Socket client) throws MalformedURLException, RemoteException, NotBoundException {  
            socket = client;  
            if(Server.gServer==null){
            	gameServer= (IGameServer) Naming.lookup("rmi://localhost:8888/gameserver");
            	Server.gServer=gameServer;
            }else{
            	gameServer=Server.gServer;
            }
            new Thread(this).start();  
            
        } 
        public void borad(String msg) {
        	try {
				writeClent(JsonUtil.writeBack(msg));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
        private void writeClent(byte json[]) throws IOException{
        	outputStream.writeInt(json.length);
        	outputStream.write(json);
        }
        private void writeClent(JSONObject json) throws IOException{
        	byte[] bt=json.toString().getBytes();
        	outputStream.writeInt(bt.length);
        	outputStream.write(bt);
        }
        private void HandleLogin(JSONObject json,DataOutputStream out) throws IOException {
        	String name=json.getString("data");
        	if(name.isEmpty()){
        		writeClent( JsonUtil.writeBack("session : username can`t be empty"));
        		return;
        	}else if(!userName.isEmpty()){
        		writeClent( JsonUtil.writeBack("session : you have login"));
        		return;
        	}
        	Server.add(name, this);
        	userName=name;
        	HandleGame(json,out);
    	}
        private void HandleLogout(JSONObject json,DataOutputStream out) throws IOException {
        	if(userName.isEmpty()){
        		writeClent(JsonUtil.writeBack("session : haven`t login"));  
        		return;
        	}
        	Server.remove(userName);
        	HandleGame(json,out);
        	userName="";
    	}
        private void HandleGame(JSONObject json,DataOutputStream out) throws IOException {
        	
        	
        	if(userName==null||userName.isEmpty()){
        		writeClent( JsonUtil.writeBack("session : not login"));
        		return;
        	}
        	
        	if(gameServer!=null)
        		writeClent( gameServer.handle(userName, json).toString().getBytes());
        	//writeClent(JsonUtil.msgJson("session : can`t handle").toString().getBytes());
    	}
        public void run() {  
        	 
            try {  
                // 读取客户端数据  
            	System.out.println("客户端数据已经连接");

            	String strInputstream ="";         
            	inputStream =new DataInputStream(socket.getInputStream());     
            	outputStream = new DataOutputStream(socket.getOutputStream());
            	ByteArrayOutputStream baos = new ByteArrayOutputStream();
            	writeClent(JsonUtil.writeBack("welcom"));

            	System.out.println("write out");
                byte[] by = new byte[2048];
            	int n;
            	boolean isRun=true;
            	while(isRun){
            		int size=inputStream.readInt();
            		System.out.println("接受到的数据长度为int："+size);
            		int cnt=0;
	                while(cnt<size){
	                	n=inputStream.read(by);
	                	if(n!=-1){
	                		cnt+=n;
	                		baos.write(by,0,n);
	                	}	
	                }
	                strInputstream = new String(baos.toByteArray());
	                System.out.println("接受到的数据长度为："+strInputstream);
	                baos.reset();
	                // 处理客户端数据  
	                //将socket接受到的数据还原为JSONObject
	                JSONObject json = new JSONObject(strInputstream); 
            	
	                String op =json.getString("op");
	                String data=json.getString("data");
	                if(op==null||data==null||op.isEmpty()||data.isEmpty())
	                	outputStream.write(JsonUtil.writeBack("session : empty operation or data"));
	                System.out.println(json+" from "+socket.getPort());
	                switch(op){
	                	case "login":HandleLogin(json,outputStream);break;
	                	case "logout":HandleLogout(json,outputStream);break;
	                	default :HandleGame(json,outputStream);
	                } 
	                
	                
            	}
            	
            } catch (Exception e) {  
                System.out.println("服务器 run 异常: " + e.getMessage());  
            } finally {  
            	if(!userName.isEmpty()){
            		Server.remove(userName);
            	}
                if (socket != null) {  
                    try {  
                        socket.close();  
                    } catch (Exception e) {  
                        socket = null;  
                        System.out.println("服务端 finally 异常:" + e.getMessage());  
                    }  
                }  
            } 
        }  
    }
	@Override
	public void broadCast(String[] ulist, String msg) throws RemoteException {
		// TODO Auto-generated method stub
		if(ulist==null)
			return;
		synchronized (handlerThreads) {
			for(String s:ulist){
				handlerThreads.get(s).borad(msg);
			}
		}
		
	}  
}  